/* tripl/arch/x86_64/asm.c 
 * 
 * This file is part of tripl. 
 * 
 * tripl is free software: you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation, either version 3 of the License, or 
 * (at your option) any later version. 
 * 
 * tripl is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 * GNU General Public License for more details. 
 * 
 * You should have received a copy of the GNU General Public License 
 * along with tripl. If not, see <https://www.gnu.org/licenses/>
 */ 




#include <stdio.h>
#include <string.h>

#include <klist.h>
#include <tripl/tripl.h>
#include <tripl/limits.h>
#include <tripl/arch.h>



struct x86_64_context {
	int stkindex;
};


#define current_private 	((struct x86_64_context *) current->private_data)

struct klist_node globvars;


__ll_asm const static char asm_head[] = {
	"	.file \"%s\"\n"
	"	.text\n"

	"	.globl 	_start\n"
	"_start:\n"
	"	/* call main and exit */\n"
	"	call 	main\n"
	"	movq 	%%rax, %%rbx\n"
	"	movq 	$1, %%rax\n"
	"	/* exit */\n"
	"	int 	$0x80\n\n"

	"	.globl 	main\n"
	/* use -x(%rbp) to access */
	"main:	pushq 	%%rbp\n"
	"	movq 	%%rsp, %%rbp\n"
};


__ll_asm const static char global_var[] = {
	"	.data\n"
	"	.globl 	%s\n"
	"%s: 	.quad 	%ld\n"
	"	.text\n"
};


__ll_asm const static char stack_var[] = {
	"	movq 	$%ld, -%d(%%rbp)\n"
};


/*__ll_asm const static char wr_stkvar[] = {
	"	movq 	$%d, -%d(%%rbp)\n"
};*/


/*__ll_asm const static char wr_glbvar[] = {
	"	movq 	$%d, %s(%%rip)\n"
};*/


/*__ll_asm const static char noarg_funcall[] = {
	"	call	%s\n"
};*/


__ll_asm const static char funcend[] = {
	"	popq 	%%rbp\n"
	"	ret\n"
};


__init int x86_64_init_asm(void) {
	current->private_data = malloc(sizeof(struct x86_64_context));
	current_private->stkindex = 1;

	klist_init(&stack);
	klist_init(&globvars);

	printf(asm_head, fname);

	return 0;
}


__init int x86_64_asm_fin(void) {
	printf(funcend);

	return 0;
}


__arch int x86_64_new_var(char *name, long value, int attr) {
	if (attr & 1) {
		/* global variable */

		printf(global_var, name, name, value);

		__push_nr(&globvars, value, name, attr);

		return 0;
	}

	/* local variable */

	printf(stack_var, value, current_private->stkindex << 3);
	push_nr(current_private->stkindex, name, attr);

	current_private->stkindex++;

	return 0;
}


